Skip to content

[WIP] Feature/dex slipage#1015

Open
DiRaiks wants to merge 31 commits intodevelopfrom
feature/dex-slipage
Open

[WIP] Feature/dex slipage#1015
DiRaiks wants to merge 31 commits intodevelopfrom
feature/dex-slipage

Conversation

@DiRaiks
Copy link
Copy Markdown
Contributor

@DiRaiks DiRaiks commented Apr 13, 2026

Description

Demo

Code review notes

Testing notes

Checklist:

  • Checked the changes locally.
  • Created / updated analytics events.
  • Created / updated the technical documentation (README.md / docs / etc.).
  • Affects / requires changes in other services (Matomo / Sentry / CloudFlare / etc.).

DiRaiks added 12 commits April 13, 2026 08:03
…drawals

Client-side trade protection for the CowSwap DEX integration that
detects anomalous quotes before users confirm swaps.

- Fiat deviation check: compares CowSwap sell/buy fiat values
- Chainlink oracle verification: cross-checks prices against on-chain feeds
- Partner fee (0.3%) subtracted from deviations (known cost, not anomaly)
- Three severity levels: warning (banner), danger (modal), blocked (modal, no proceed)
- wstETH → stETH rate conversion via on-chain stEthPerToken call
- Token whitelist and recipient validation
- Small trade cap ($50) prevents false positives from fixed costs
- QA overrides via localStorage (gated by ENABLE_QA_HELPERS build flag)
- 55 unit tests for pure utility functions
…rror

The ref was declared before the hook that provides showBlockedMessage,
causing a ReferenceError at runtime.
The 'blocked' modal (red, "Trade blocked for your protection") was too
alarming for a simple business limit. New 'limit' level uses grey
styling with "Amount limit reached" title — still blocks the action
but without implying a security threat.
…component

Encapsulates sell-amount ref, limit check, and modal display inside
useTradeGuard. Component now calls reportSellAmount() and checkSellLimit()
instead of managing refs and callbacks directly.
@DiRaiks DiRaiks requested a review from a team as a code owner April 13, 2026 11:08
DiRaiks added 17 commits April 13, 2026 14:19
…guard

- Collapse warning→danger, danger→blocked thresholds (fiatDanger=4%, fiatBlock=5%, oracleBlock=4%)
- Remove MAX_PLAUSIBLE_GAIN_RATIO check (dead code, messages never displayed)
- Remove warning from TradeGuardLevel type, LEVEL_ORDER, modal titles
- Fix TITLE_TEXT fallback from .warning to .danger
- Update all tests (73 pass)
Intercept eth_signTypedData_v4 in the provider and verify that the
CowSwap order's receiver matches the wallet address and tokens are
in the whitelist. Prevents signing a manipulated order even if the
onBeforeTrade payload was spoofed.
Compare the signed order's sellAmount and buyAmount against the
onBeforeTrade payload that was validated by the trade guard.
Strict match — no tolerance — since CowSwap does not re-quote
between the hook and the signing request.

- Store validated trade snapshot (tokens, amounts) in ref after validation
- verifySignedOrder callback: checks addresses + amounts
- Token decimals map for unit→raw conversion (all whitelisted tokens)
- Provider calls verifySignedOrder instead of static verifyOrderFields
Demo feedback:
- Remove danger level entirely — all suspicious trades are blocked
- fiatDeviationBlock threshold lowered to 4% (was 5%)
- Remove "Proceed anyway" button and orange modal styling
- Oracle badge: skip oracle check for structural blocks (token/recipient/
  wallet/limit) to prevent misleading "Verified by Chainlink" on unrelated
  blocks
- Remove sell limit banner (keep modal on button press)
- Add isStructural flag to analyzeParams for oracle skip logic
- Remove small trade cap (no danger to downgrade to)
- Remove SellLimitStatus from hook exports
…uard

CowSwap's onBeforeTrade payload never includes fiat amounts and
minimumReceiveBuyAmount always equals buyTokenAmount, making these
checks dead code. All price verification is now delegated to the
Chainlink oracle. analyzeParams is now purely structural (token
whitelist, recipient, sell limit).
Store last ON_CHANGE_TRADE_PARAMS payload in ref and run analyzeParams
(token whitelist, recipient, sell limit) on onBeforeApproval — blocks
invalid trades before the approve transaction is sent.
…check, double QA override)

- Add 'limit' to LEVEL_ORDER so QA escalation handles all levels correctly
- Wrap BigInt() in verifyOrderAmounts with try/catch for malformed input
- Guard empty walletAddress in verifySignedOrder before calling verifyOrderFields
- Remove redundant inline QA clamp of minSellUnitsToTriggerOracle (already handled by readThresholds)
…l without params

- Fix typo: safe-parce-decimal.ts → safe-parse-decimal.ts
- Add 25 tests for verifyOrderFields, verifyOrderAmounts, parseOrderFromSignRequest
- Block approval when ON_CHANGE_TRADE_PARAMS has not fired yet (fail-closed)
- C-1: verifySignedOrder now rejects when no validated trade snapshot
  exists (fail-closed instead of silent pass)
- C-2: Clear lastValidatedTradeRef at start of validateTrade to prevent
  stale snapshot from a concurrent/previous call
- H-1: Replace Number() with safeParseDecimal in reportTradeParams to
  reject scientific notation consistently
- H-2: Add typeof string checks in parseOrderFromSignRequest before
  casting to OrderFields (prevents TypeError on non-string fields)
- H-3: verifyOrderAmounts now rejects when token decimals are unknown
  (fail-closed instead of silently skipping amount check)
- Add walletAddress guard to validateApproval (blocks when wallet
  disconnected, consistent with validateTrade)
DiRaiks added 2 commits April 16, 2026 11:24
@cowprotocol/widget-lib v2 accesses document at module scope,
breaking Next.js SSR. Use next/dynamic with ssr:false to defer
the entire widget tree to client-side only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant